﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace UNSWThink
{
   /// <summary>
   /// Windows form that adds or edits class information
   /// </summary>
   public partial class AddEditClassForm : Form
   {
      private DBConnection dbConnection;
      private DataSet instructorData;
      private DataTable relatedClasses;
      private DataTable relatedAccounts;

      private int instructorID;
      private int classID;
      private ArrayList courseIDs;
      private ArrayList courseStrings;

      private bool mode;
      private bool usingAccount;
      private DateTime currentTimestamp;
      private string password;
      private int classAccountID;
      private int startHour;
      private int startMinute;
      private int startDay;
      private int startMonth;
      private int startYear;
      private int finishHour;
      private int finishMinute;
      private int finishDay;
      private int finishMonth;
      private int finishYear;

      /// <summary>
      /// Default constructor
      /// </summary>
      /// <param name="mode">
      /// States the type of mode the form is to function as
      /// </param>
      /// <param name="dbConnection">
      /// Database connection interface for making queries to a database
      /// </param>
      /// <param name="instructorID">
      /// ID of the logged in instructor
      /// </param>
      /// <param name="classID">
      /// ID of class that is to be modified
      /// </param>
      /// <param name="courseIDs">
      /// IDs of the all of the possible courses</param>
      /// <param name="courseStrings">
      /// Strings of all the possible courses
      /// </param>
      /// <param name="instructorData">
      /// Data set containing all of instructor related data
      /// </param>
      public AddEditClassForm(bool mode, DBConnection dbConnection,
         int instructorID, int classID, ArrayList courseIDs, ArrayList courseStrings, 
         DataSet instructorData)
      {
         InitializeComponent();

         this.mode = mode;
         this.dbConnection = dbConnection;
         this.instructorID = instructorID;
         this.courseIDs = courseIDs;
         this.courseStrings = courseStrings;
         this.instructorData = instructorData;
         this.relatedClasses = instructorData.Tables["Class"];
         this.relatedAccounts = instructorData.Tables["ClassAccount"];

         this.usingAccount = false;
         this.password = String.Empty;
         this.classAccountID = 0;
         this.startHour = 0;
         this.startMinute = 0;
         this.startDay = 1;
         this.startMonth = 1;
         this.startYear = 1;
         this.finishHour = 0;
         this.finishMinute = 0;
         this.finishDay = 1;
         this.finishMonth = 1;
         this.finishYear = 1;

         if (this.mode == Defs.ADD_MODE)
         {
            this.classID = 0;
         }
         else
         {
            this.classID = classID;
         }
      }

      #region WINDOWS FORM EVENTS

      private void AddEditClassForm_Load(object sender, EventArgs e)
      {
         // if related tables are not correct, keep form empty and only have 'Cancel' button enabled
         if ((!HelperMethods.CheckColumnsExists(relatedClasses, Defs.CLASS_COLUMN_NAMES)) &&
             (!HelperMethods.CheckColumnsExists(relatedAccounts, Defs.CLASS_ACCOUNT_COLUMN_NAMES)))
         {
            buttonCourseWeekBack.Enabled = false;
            buttonCourseWeekNext.Enabled = false;
            buttonTimeBack.Enabled = false;
            buttonTimeNext.Enabled = false;
            buttonInfoBack.Enabled = false;
            buttonInfoFinish.Enabled = false;

            return;
         }

         comboBoxCourse.DataSource = courseStrings;

         if (mode == Defs.ADD_MODE)
         {
            // loading current time
            currentTimestamp = DateTime.Now;
            startYear = currentTimestamp.Year;
            startMonth = currentTimestamp.Month;
            startDay = currentTimestamp.Day;
            startHour = currentTimestamp.Hour;
            startMinute = currentTimestamp.Minute;
            finishYear = currentTimestamp.Year;
            finishMonth = currentTimestamp.Month;
            finishDay = currentTimestamp.Day;
            finishHour = currentTimestamp.Hour;
            finishMinute = currentTimestamp.Minute;

            SetStartNumericUpDown();
            //SetFinishNumericUpDown();
         }
         else
         {
            // get class table index
            int classIndex = HelperMethods.GetIndexOfTableID(relatedClasses, classID);

            // get class information
            int courseID = (int)relatedClasses.Rows[classIndex]["course"];
            DateTime startTime = (DateTime)relatedClasses.Rows[classIndex]["starttime"];
            DateTime finishTime = (DateTime)relatedClasses.Rows[classIndex]["finishtime"];
            int week = (int)relatedClasses.Rows[classIndex]["week"];
            string name = relatedClasses.Rows[classIndex]["name"].ToString();
            string comments = relatedClasses.Rows[classIndex]["comments"].ToString();

            // load existing course
            radioButtonExistingCourse.Checked = true;
            for (int i = 0; i < courseIDs.Count; i++)
            {
               if ((int)courseIDs[i] == courseID)
               {
                  comboBoxCourse.SelectedIndex = i;
                  break;
               }
            }

            // load existing week
            if (week == Defs.MISC_WEEK_INT)
            {
               radioButtonMiscWeek.Checked = true;
            }
            else if (week == Defs.REV_WEEK_INT)
            {
               radioButtonRevWeek.Checked = true;
            }
            else
            {
               radioButtonWeekNo.Checked = true;
               numericUpDownWeek.Value = week;
            }

            // load existing start and finish dates and times
            startYear = startTime.Year;
            startMonth = startTime.Month;
            startDay = startTime.Day;
            startHour = startTime.Hour;
            startMinute = startTime.Minute;
            finishYear = finishTime.Year;
            finishMonth = finishTime.Month;
            finishDay = finishTime.Day;
            finishHour = finishTime.Hour;
            finishMinute = finishTime.Minute;
            SetStartNumericUpDown();

            // load existing class account information
            usingAccount = false;
            radioButtonNo.Checked = true;
            password = String.Empty;
            for (int i = 0; i < relatedAccounts.Rows.Count; i++)
            {
               // if account exists, then change account variables
               if ((int)relatedAccounts.Rows[i]["class"] == classID)
               {
                  usingAccount = true;
                  radioButtonYes.Checked = true;
                  password = relatedAccounts.Rows[i]["password"].ToString();
                  classAccountID = (int)relatedAccounts.Rows[i]["id"];
                  break;
               }
            }

            // load existing class name and comments
            textBoxName.Text = name;
            textBoxComments.Text = comments;
         }
      }

      #endregion

      #region CONTROL EVENTS

      private void buttonCourseWeekNext_Click(object sender, EventArgs e)
      {
         wizardPages1.SelectTab("tabPageTime");
      }

      private void buttonCancelCourseWeek_Click(object sender, EventArgs e)
      {
         CloseForm();
      }

      private void buttonTimeBack_Click(object sender, EventArgs e)
      {
         wizardPages1.SelectTab("tabPageCourseWeek");
      }

      private void buttonTimeNext_Click(object sender, EventArgs e)
      {
         wizardPages1.SelectTab("tabPageInfo");
      }

      private void buttonTimeCancel_Click(object sender, EventArgs e)
      {
         CloseForm();
      }

      private void buttonInfoBack_Click(object sender, EventArgs e)
      {
         wizardPages1.SelectTab("tabPageTime");
      }

      private void buttonInfoFinish_Click(object sender, EventArgs e)
      {
         if (CheckCompleted())
         {
            // get selected course ID
            int courseID = 0;
            if (radioButtonNoCourse.Checked)
            {
               courseID = Defs.NO_COURSE_ID;

               // check to see if no course exists in the course data table
               if (!CheckNoCourseExists())
               {
                  // get no course rows from db
                  DataSet noCourseRows = dbConnection.GetNoCourseRows();

                  // insert no course rows into program's memory
                  foreach (DataTable table in noCourseRows.Tables)
                  {
                     if (table.Rows.Count > 0)
                     {
                        instructorData.Tables[table.TableName].Rows.Add(table.Rows[0].ItemArray);
                     }
                  }
               }
            }
            else
            {
               courseID = (int)courseIDs[comboBoxCourse.SelectedIndex];
            }

            // get start and finish timestamps
            string tempStringTimestamp = HelperMethods.DateValuesToString(startYear, startMonth, 
               startDay, startHour, startMinute, 0);
            DateTime startTimestamp;
            if (!DateTime.TryParse(tempStringTimestamp, out startTimestamp))
            {
               MessageBox.Show("Could not parse start date and time values", "Date and time parse error",
                  MessageBoxButtons.OK, MessageBoxIcon.Hand);
               return;
            }

            tempStringTimestamp = HelperMethods.DateValuesToString(finishYear, finishMonth,
               finishDay, finishHour, finishMinute, 0);
            DateTime finishTimestamp;
            if (!DateTime.TryParse(tempStringTimestamp, out finishTimestamp))
            {
               MessageBox.Show("Could not parse finish date and time values", "Date and time parse error",
                  MessageBoxButtons.OK, MessageBoxIcon.Hand);
               return;
            }

            // get week number
            int week = 0;
            if (radioButtonMiscWeek.Checked)
            {
               week = Defs.MISC_WEEK_INT;
            }
            else if (radioButtonRevWeek.Checked)
            {
               week = Defs.REV_WEEK_INT;
            }
            else
            {
               week = Decimal.ToInt32(numericUpDownWeek.Value);
            }

            // get class name and comments
            string name = "";
            if (textBoxName.Text == String.Empty)
            {
               name = Defs.DEFAULT_STRING;
            }
            else
            {
               name = textBoxName.Text;
            }

            string comments = "";
            if (textBoxComments.Text == String.Empty)
            {
               comments = Defs.DEFAULT_STRING;
            }
            else
            {
               comments = textBoxComments.Text;
            }

            // create class name and value arrays
            string[] classColumnNames = 
             { "course", 
               "starttime", 
               "finishtime", 
               "week", 
               "name", 
               "comments" };
            object[] classValues = 
             { courseID,
               startTimestamp,
               finishTimestamp,
               week,
               name,
               comments };

            // create class account name and value arrays
            string[] accountColumnNames =
             { "class",
               "password" };
            object[] accountValues =
             { classID,
               password };

            if (mode == Defs.ADD_MODE)
            {
               // insert class into db
               int inserted = dbConnection.InsertRecord("Class", classColumnNames, classValues);
               if (inserted > 0)
               {
                  // insert class into program's memory
                  string[] newClassNames = HelperMethods.CreateNewStringArray("id", classColumnNames);
                  object[] newClassValues = HelperMethods.CreateNewObjectArray(inserted, classValues);
                  HelperMethods.InsertIntoTable(relatedClasses, newClassNames, newClassValues);

                  string[] teachesColumnNames = 
                   { "account",
                     "class" };
                  object[] teachesValues = 
                   { instructorID,
                     inserted };

                  // update teaches table so that class is accessible to instructor
                  int insertedTeaches = dbConnection.InsertRecord("Teaches", 
                     teachesColumnNames, teachesValues);
                  if (insertedTeaches > 0)
                  {

                     // insert class account info into db and program memory if 'yes' is checked
                     if (radioButtonYes.Checked)
                     {
                        // insert class account into db
                        accountValues[0] = inserted;
                        inserted = dbConnection.InsertRecord("ClassAccount",
                           accountColumnNames, accountValues);
                        if (inserted > 0)
                        {
                           // insert class account into program's memory
                           string[] newAccountNames = HelperMethods.CreateNewStringArray("id",
                              accountColumnNames);
                           object[] newAccountValues = HelperMethods.CreateNewObjectArray(inserted,
                              accountValues);
                           HelperMethods.InsertIntoTable(relatedAccounts, newAccountNames, 
                              newAccountValues);
                        }
                     }
                  }
               }
            }
            else
            {
               // update class into db
               bool updated = dbConnection.UpdateRecord("Class", classID, classColumnNames, classValues);
               if (updated)
               {
                  // update class in program's memory
                  int rowIndex = HelperMethods.GetIndexOfTableID(relatedClasses, classID);
                  HelperMethods.UpdateTable(relatedClasses, rowIndex, classColumnNames, classValues);

                  // insert/update/delete depending on the account option and original account state
                  if (radioButtonYes.Checked)
                  {
                     if (usingAccount)
                     {
                        // update class account into db
                        updated = dbConnection.UpdateRecord("ClassAccount", classAccountID, 
                           accountColumnNames, accountValues);
                        // update class account into program's memory
                        rowIndex = HelperMethods.GetIndexOfTableID(relatedAccounts, classAccountID);
                        HelperMethods.UpdateTable(relatedAccounts, rowIndex, 
                           accountColumnNames, accountValues);
                     }
                     else
                     {
                        // insert class account into db
                        int inserted = dbConnection.InsertRecord("ClassAccount",
                           accountColumnNames, accountValues);
                        if (inserted > 0)
                        {
                           // insert class account into program's memory
                           string[] newAccountNames = HelperMethods.CreateNewStringArray("id",
                              accountColumnNames);
                           object[] newAccountValues = HelperMethods.CreateNewObjectArray(inserted,
                              accountValues);
                           HelperMethods.InsertIntoTable(relatedAccounts, newAccountNames,
                              newAccountValues);
                        }
                     }
                  }
                  else
                  {
                     if (usingAccount)
                     {
                        // delete class account into db
                        bool deleted = dbConnection.DeleteRecord("ClassAccount", classAccountID);
                        if (deleted)
                        {
                           // delete class account into program's memory
                           rowIndex = HelperMethods.GetIndexOfTableID(relatedAccounts, classAccountID);
                           HelperMethods.DeleteFromTable(relatedAccounts, rowIndex);
                        }
                     }
                  }
               }
            }

            CloseForm();
         }
      }

      private void buttonInfoCancel_Click(object sender, EventArgs e)
      {
         CloseForm();
      }

      private void numericUpDownYear_ValueChanged(object sender, EventArgs e)
      {
         numericUpDownDay.Maximum = DateTime.DaysInMonth(Decimal.ToInt32(numericUpDownYear.Value),
            Decimal.ToInt32(numericUpDownMonth.Value));

         if (radioButtonStart.Checked)
         {
            startYear = Decimal.ToInt32(numericUpDownYear.Value);
         }
         else
         {
            finishYear = Decimal.ToInt32(numericUpDownYear.Value);
         }

         UpdateMonthCalendar();
      }

      private void numericUpDownMonth_ValueChanged(object sender, EventArgs e)
      {
         numericUpDownDay.Maximum = DateTime.DaysInMonth(Decimal.ToInt32(numericUpDownYear.Value),
            Decimal.ToInt32(numericUpDownMonth.Value));

         if (radioButtonStart.Checked)
         {
            startMonth = Decimal.ToInt32(numericUpDownMonth.Value);
         }
         else
         {
            finishMonth = Decimal.ToInt32(numericUpDownMonth.Value);
         }

         UpdateMonthCalendar();
      }

      private void numericUpDownDay_ValueChanged(object sender, EventArgs e)
      {
         if (radioButtonStart.Checked)
         {
            startDay = Decimal.ToInt32(numericUpDownDay.Value);
         }
         else
         {
            finishDay = Decimal.ToInt32(numericUpDownDay.Value);
         }

         UpdateMonthCalendar();
      }

      private void numericUpDownHour_ValueChanged(object sender, EventArgs e)
      {
         if (radioButtonStart.Checked)
         {
            startHour = Decimal.ToInt32(numericUpDownHour.Value);
         }
         else
         {
            finishHour = Decimal.ToInt32(numericUpDownHour.Value);
         }
      }

      private void numericUpDownMinute_ValueChanged(object sender, EventArgs e)
      {
         if (radioButtonStart.Checked)
         {
            startMinute = Decimal.ToInt32(numericUpDownMinute.Value);
         }
         else
         {
            finishMinute = Decimal.ToInt32(numericUpDownMinute.Value);
         }
      }

      private void radioButtonStart_CheckedChanged(object sender, EventArgs e)
      {
         SetStartNumericUpDown();
      }

      private void radioButtonFinish_CheckedChanged(object sender, EventArgs e)
      {
         SetFinishNumericUpDown();
      }

      private void monthCalendar_DateChanged(object sender, DateRangeEventArgs e)
      {
         DateTime temp = monthCalendar.SelectionStart;
         numericUpDownYear.Value = temp.Year;
         numericUpDownMonth.Value = temp.Month;
         numericUpDownDay.Value = temp.Day;
      }

      private void buttonInfoPassword_Click(object sender, EventArgs e)
      {
         ClassAccountPasswordForm passwordForm = new ClassAccountPasswordForm();
         passwordForm.Owner = this;
         passwordForm.ShowDialog();
      }

      private void radioButtonYes_CheckedChanged(object sender, EventArgs e)
      {
         buttonInfoPassword.Enabled = true;
      }

      private void radioButtonNo_CheckedChanged(object sender, EventArgs e)
      {
         buttonInfoPassword.Enabled = false;
      }
      
      #endregion

      #region HELPER METHODS

      private void CloseForm()
      {
         this.Close();
      }

      private bool CheckCompleted()
      {
         if ((!radioButtonNoCourse.Checked) &&
             (!radioButtonExistingCourse.Checked))
         {
            MessageBox.Show("No course options have been selected", "No course options", 
               MessageBoxButtons.OK, MessageBoxIcon.Hand);
            return false;
         }

         if (!radioButtonNoCourse.Checked)
         {
            if (radioButtonExistingCourse.Checked)
            {
               if (comboBoxCourse.SelectedIndex < 0)
               {
                  MessageBox.Show("No course has been selected from the drop down list", "No course", 
                     MessageBoxButtons.OK, MessageBoxIcon.Hand);
                  return false;
               }
            }
         }

         if ((!radioButtonMiscWeek.Checked) && 
             (!radioButtonRevWeek.Checked) && 
             (!radioButtonWeekNo.Checked))
         {
            MessageBox.Show("No week options have been selected", "No week options", 
               MessageBoxButtons.OK, MessageBoxIcon.Hand);
            return false;
         }

         if ((!radioButtonMiscWeek.Checked) && 
             (!radioButtonRevWeek.Checked))
         {
            if (radioButtonWeekNo.Checked)
            {
               if ((numericUpDownWeek.Value < numericUpDownWeek.Minimum) ||
                   (numericUpDownWeek.Value > numericUpDownWeek.Maximum))
               {
                  MessageBox.Show("An invalid week has been selected", "Invalid week", 
                     MessageBoxButtons.OK, MessageBoxIcon.Hand);
                  return false;
               }
            }
         }

         string startStringTimestamp = HelperMethods.DateValuesToString(startYear, startMonth, startDay, startHour, startMinute, 0);
         DateTime tempTimestamp;
         if (!DateTime.TryParse(startStringTimestamp, out tempTimestamp))
         {
            MessageBox.Show("The current start date and time is not valid", "Invalid start date and time",
               MessageBoxButtons.OK, MessageBoxIcon.Hand);
            return false;
         }

         string finishStringTimestamp = HelperMethods.DateValuesToString(finishYear, finishMonth, finishDay, finishHour, finishMinute, 0);
         if (!DateTime.TryParse(finishStringTimestamp, out tempTimestamp))
         {
            MessageBox.Show("The current finish date and time is not valid", "Invalid finish date and time",
               MessageBoxButtons.OK, MessageBoxIcon.Hand);
            return false;
         }

         if ((!radioButtonYes.Checked) &&
             (!radioButtonNo.Checked))
         {
            MessageBox.Show("Class account has not been specified", "Unspecified class account",
               MessageBoxButtons.OK, MessageBoxIcon.Hand);
            return false;
         }

         if (radioButtonYes.Checked)
         {
            if (password == String.Empty)
            {
               MessageBox.Show("Password for a class account has not been set", "No password",
               MessageBoxButtons.OK, MessageBoxIcon.Hand);
               return false;
            }
         }

         return true;
      }

      private void SetStartNumericUpDown()
      {
         numericUpDownYear.Value = startYear;
         numericUpDownMonth.Value = startMonth;
         numericUpDownDay.Value = startDay;
         numericUpDownHour.Value = startHour;
         numericUpDownMinute.Value = startMinute;
      }

      private void SetFinishNumericUpDown()
      {
         numericUpDownYear.Value = finishYear;
         numericUpDownMonth.Value = finishMonth;
         numericUpDownDay.Value = finishDay;
         numericUpDownHour.Value = finishHour;
         numericUpDownMinute.Value = finishMinute;
      }

      private void UpdateMonthCalendar()
      {
         if (radioButtonStart.Checked)
         {
            string tempStartString = HelperMethods.DateValuesToString(startYear, startMonth, startDay,
               startHour, startMinute, 0);
            DateTime tempStart;
            DateTime.TryParse(tempStartString, out tempStart);
            monthCalendar.SetDate(tempStart);
         }
         else
         {
            string tempFinishString = HelperMethods.DateValuesToString(finishYear, finishMonth, finishDay,
               finishHour, finishMinute, 0);
            DateTime tempFinish;
            DateTime.TryParse(tempFinishString, out tempFinish);
            monthCalendar.SetDate(tempFinish);
         }
      }

      private bool CheckNoCourseExists()
      {
         for (int i = 0; i < courseIDs.Count; i++)
         {
            if ((int)courseIDs[i] == Defs.NO_COURSE_ID)
            {
               return true;
            }
         }

         return false;
      }

      #endregion

      #region PROPERTIES

      /// <summary>
      /// Sets the password porperty
      /// </summary>
      public string Password
      {
         set
         {
            password = value;
         }
      }

      #endregion

   }
}
